/*
 * UMLSynch plugin for Eclipse-CDT
 * http://umlsynch.googlecode.com
 *
 * Copyright 2008-2010, Evgeny Alexeyev
 * Licensed under the EPL - v1.0
 * http://www.eclipse.org/legal/epl-v10.html
 *
 */

package com.googlecode.umlsynch.eclipse.astutils;


import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.index.IndexFilter;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;

import com.googlecode.umlsynch.rpc.TClassDescriptor;
import com.googlecode.umlsynch.rpc.TFileDescriptor;
import com.googlecode.umlsynch.rpc.base.TDebug;


public class ASTUtils {

	private TDebug debug = new TDebug(null); 
	
	TranslationUnitUtils TU = TranslationUnitUtils.GetInstance();
	
	private static ASTUtils singletone;

	public static ASTUtils instance()
	{		
		if (singletone == null)
		{
			singletone = new ASTUtils();			
		}		
		return singletone;
	}

	public class ListChecker implements Runnable {
		public String[] checklist ;
		public String selected;
		
		public void run(){
			IWorkbenchPage page = null;

			IWorkbenchWindow awin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
			if (awin == null)
			{
				awin = PlatformUI.getWorkbench().getWorkbenchWindows()[0];
			}
			if (awin != null)
			{
			    IWorkbenchPage pg = awin.getActivePage();

				//FileSelectDialog fopd = new FileSelectDialog(awin.getShell());

				//fopd.setFileList(checklist);
				//selected = fopd.open();
			}

		}
	};

	

	public class FileOpener implements Runnable {
		public String name;
		public void run(){
			IWorkbenchWindow[] wins = PlatformUI.getWorkbench().getWorkbenchWindows();
			for (int www=0; www<wins.length; www++) {
				if (wins[www].equals(PlatformUI.getWorkbench().getActiveWorkbenchWindow()))
				{
					debug.Note("Active WB windows");	
				}
				else
				{
					debug.Note("NOT Active WB windows");					    		
				}
				IWorkbenchPage[] pg = wins[www].getPages();
				for (int wr=0; wr < pg.length; wr++){
					if (pg[wr].equals(wins[www].getActivePage()))
					{
						debug.Note("Active page");
					}
					debug.Note("page = " + pg[wr].getLabel());
					try {						
						File fileToOpen = new File(name);
						IFileStore fileStore = EFS.getLocalFileSystem().getStore(fileToOpen.toURI());
						debug.Debug("Open file:" + fileStore.toString());
						debug.Debug("Open file:" + fileStore.getName());
						IDE.openEditorOnFileStore( pg[wr], fileStore );
						
					} catch ( PartInitException e ) {
						debug.Error("Open file exception: " + e.getLocalizedMessage());
					}

				}
			}

		}

	};


	private boolean IsAcceptableFile(String filename, String[] paths) {
		if ((paths == null) || (paths.length <=0)) {
			debug.Debug("IsAcceptableFile= true");
			return true;
		}
		

		for (int i =0; i<paths.length; ++i) {
			debug.Debug("Paths: " + paths[i]);
			if (filename.compareTo(paths[i]) == paths[i].length()){
				return true;
			}
		}
		
		return false;
	}

	public void GetClassFile(TClassDescriptor desc)
	{
		if (desc == null)
			return;
		
		ICModel cModel= CoreModel.getDefault().getCModel();
		IIndexManager manager = CCorePlugin.getIndexManager();

		ICProject cProject = cModel.getCProject(desc.file.project);

		if (cProject == null) {
			debug.Error("Can find cModel of project: " + desc.file.project);
		}
		
		String prefix = cProject.getLocationURI().toString();
		prefix = prefix.substring(6, prefix.length());
		FileOpener fopener = new FileOpener();
		fopener.name = prefix + "/" + desc.file.path;
		PlatformUI.getWorkbench().getDisplay().syncExec(fopener);
	}

	public TClassDescriptor IdentifyClass(TClassDescriptor desc)
	{
		debug.Note("name: " + desc.name +
				"\n proj:" + desc.file.project);
		
		if ((desc.file.path != null)
				&& (!desc.file.path.isEmpty()))
			return desc;
						
		IIndex index = this.GetProjectIndex(desc);
		ICPPClassType classBinding = this.GetNestedClassBinding(desc);

		if ((index == null) || (classBinding == null)) {
			debug.Error("Null index or binding");
			return null;
		}

		ListChecker chl = new ListChecker();		

		try {			
			index.acquireReadLock(); // release lock on finally
			IIndexName[] names = index.findNames(classBinding, IIndex.FIND_DEFINITIONS);

			if (names != null && names.length > 1) {
				chl.checklist = new String[names.length];

				// complete the list of definitions
				for  (int j = 0; j < names.length; j++) { 
					String path = names[j].getFileLocation().getFileName();
					int projNamePos = path.lastIndexOf(desc.file.project) + 
							desc.file.project.length() + 1; 
					chl.checklist[j] = path.substring(projNamePos, path.length());					
				}

				PlatformUI.getWorkbench().getDisplay().syncExec(chl);

				if (chl.selected == null)
					return null;

				desc.file.path = chl.selected;

			} else // There is only one instance of class exists !!!
				if (names.length == 1) {
					String path = names[0].getFileLocation().getFileName();
					
					int projNamePos = path.indexOf(desc.file.project) + 
							desc.file.project.length() + 1; 
					desc.file.path = path.substring(projNamePos, path.length());
					
				}
		} catch (CoreException e) {
			debug.Error("Exception:" + e.getStackTrace()[0].getFileName());
		} catch (InterruptedException e) {
			debug.Error("Exception:" + e.getStackTrace()[0].getFileName());
		} finally {
			if (index != null)
				index.releaseReadLock();
		}

		return (desc.file.path != null) ? desc:null;
	}
	
	public TClassDescriptor[] GetClassBases(TClassDescriptor classData)
	{
		// Class was identified on the previous stage
		return TU.FindClassBases(classData);
	}
	public TClassDescriptor[] GetNestedClasses(TClassDescriptor classData)
	{
		ICPPClassType class1 = this.GetNestedClassBinding(classData);
		if (class1 == null) {
			return null;
		}
		
		try {
			ICPPClassType[] nested = class1.getNestedClasses();
			if (nested.length > 0)
			{
				TClassDescriptor[] ret = new TClassDescriptor[nested.length];
			
				for (int i = 0; i< nested.length; i++)
				{
					ret[i] = new TClassDescriptor();
					ret[i].name = classData.name + "::" +nested[i].getName();
					ret[i].file.project = classData.file.project;
					
				}
				return ret;
			}
		} catch (DOMException e) {
			e.printStackTrace();
		}
		
		return null;
	}

	public TClassDescriptor[] GetClassGeneralizations(TClassDescriptor classData)
	{
		ICPPClassType class1 = this.GetNestedClassBinding(classData);

		IIndex index = GetProjectIndex(classData);		

		if (class1 == null || index == null)			
			return null;

		List<TClassDescriptor> result = new ArrayList<TClassDescriptor>();
		
		try {
			index.acquireReadLock();

			TClassDescriptor[] ret = null;

			IIndexName[] refs = index.findNames(class1, index.FIND_ALL_OCCURRENCES);
			
			for (int i =0; i<refs.length; ++i) {
				debug.Error("Next: " + refs[i].getFileLocation().getFileName());
				if (refs[i].isBaseSpecifier()) {
					IIndexName def = refs[i].getEnclosingDefinition();
					
					IIndexBinding bind = index.findBinding(def);
					if (bind instanceof ICPPClassType) {

						String file = def.getFileLocation().getFileName();
						
						debug.Note("Found file: " + file);
						String path = 
							file.substring(file.indexOf(classData.file.project) + 
									classData.file.project.length() + 1, file.length()); 

						TClassDescriptor next = new TClassDescriptor();
						next.name = bind.getName();
						next.file.project = classData.file.project;
						next.file.path = path;
						
						result.add(next);				
					}
										
				}
			}
		} catch (InterruptedException e) {
		} catch (CoreException e) {
		} finally {
			if (index != null)
				index.releaseReadLock();
		}
		return TU.DynamcCastListToArray(result);
	}

	public TClassDescriptor[] GetClassFriends(TClassDescriptor classData)
	{
		IIndex index = GetProjectIndex(classData);
		ICPPClassType class1 = GetNestedClassBinding(classData);

		if (class1 == null || index == null)
			return null;

		try {
			index.acquireReadLock();

			List<TClassDescriptor> result = new ArrayList<TClassDescriptor>();

			IBinding[] friends = class1.getFriends();
			for (int i=0; i<friends.length; ++i) {
				if (friends[i] instanceof ICPPClassType) {
					IIndexName[] declarations;
					try {
						declarations = index.findDeclarations(friends[i]);
					} catch (CoreException e) {
						continue;
					}
					for (int j=0; j<declarations.length; ++j) {
						TClassDescriptor next = new TClassDescriptor();
						next.name = friends[i].getName();						
						next.file.project = classData.file.project;
						String path = declarations[j].getFileLocation().getFileName();
						int projNamePos = path.indexOf(next.file.project);
						next.name = path.substring(projNamePos, path.length());
						result.add(next);
					}
					
				}
			}

			return TU.DynamcCastListToArray(result);
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (DOMException e) {
			e.printStackTrace();
		} finally {
			if (index != null)
				index.releaseReadLock();
		}
		return null;
	}

	public boolean IsSingletoneClass(ICPPClassType class1, String filename, String projectName) {
		return (HasAssociationRelation(class1, projectName, filename, class1.getName()) >= 0);
	}
	
	public boolean IsInterface(TClassDescriptor data) {
		if (data.name.charAt(0) == 'I') {
			return true;
		}
		
		return false;
	}
	
	public TClassDescriptor[] GetClassRelation(TClassDescriptor classData, 
			String relationType, TFileDescriptor[] searchRestrictions)
	{
		boolean isAssociationSearch = false;
		boolean isAggregationSearch = false;
		boolean isDependencySearch = false;
		boolean isCompositionSearch = false;

		ICPPClassType class1 = this.GetNestedClassBinding(classData);
		
		IIndex index = this.GetProjectIndex(classData);
		
		if (class1 == null || index == null) {
			debug.Debug("R:2 NULL binding ? ");
			return null;		
		}
		
		boolean isSingletone = 
			this.IsSingletoneClass(class1, classData.file.path, classData.file.project);
		boolean isInterface = this.IsInterface(classData);
		
		debug.Debug("R:1" + relationType);
		if (relationType.equals("Association")) {
			isAssociationSearch = true;
		} else if (relationType.equals("Aggregation")) {
			isAggregationSearch = true;
			if (isSingletone) {
				debug.Note("There is no aggregation for singletone classes");
				return null;
			}
		} else if (relationType.equals("Dependency")) {
			isDependencySearch = true;
		} else if (relationType.equals("Composition")) {
			isCompositionSearch = true;
			if (isInterface) {
				debug.Note("There is no composition for Interface");
				return null;
			}
		} else {
			debug.Debug("R:1 nothing");
			return null;
		}
		

		List<ICPPClassType> aggregationList =  new ArrayList<ICPPClassType>();
		List<ICPPClassType> compositionList =  new ArrayList<ICPPClassType>();
		List<ICPPClassType> associationList =  new ArrayList<ICPPClassType>();
		List<ICPPClassType> dependencyList =  new ArrayList<ICPPClassType>();
		
		List<ICPPClassType> listOfClassReferences = new ArrayList<ICPPClassType>();
		List<String> listOfCorrespondingFileNames = new ArrayList<String>();
		List<TClassDescriptor> result = new ArrayList<TClassDescriptor>();
		
		try {
			index.acquireReadLock();

			TClassDescriptor[] ret = null;

			IIndexName[] references = index.findNames(class1, IIndex.FIND_ALL_OCCURRENCES);

			if ((references != null) && (references.length > 0))
				for (int i = 0; i< references.length; i++) {

					if (references[i].isBaseSpecifier()) {
						debug.Debug("R:3" + references[i].getFileLocation().getFileName());
						continue;
					}

					IIndexName encnames = references[i].getEnclosingDefinition();
					
					if (encnames == null) {
						encnames = this.GetClassFromFile(references[i].getFile(), index);
						
						debug.Debug("R:4" + references[i].getFileLocation().getFileName() + 
								"Line " + references[i]);
//						TU.FindClassSpecifiers(references[i].getFileLocation().getFileName(),
	//							classData, relationType);
						if (encnames == null) {
							debug.Debug("R:4: NULL");
							continue;	
						}
						
					}

					debug.Debug("R:5" + references[i].getFileLocation().getFileName());
					
					String filename = encnames.getFileLocation().getFileName();
					int pos = filename.indexOf(classData.file.project);
					filename = filename.substring(pos,filename.length());
					
					IIndexBinding bind = index.findBinding(encnames);
					ICPPClassType bindClass = null;
					
					if (bind instanceof ICPPMethod) {
						ICPPMethod methf = (ICPPMethod)bind;
						bindClass = methf.getClassOwner();
					}
					
					if (bind instanceof ICPPField) {
						ICPPField field = (ICPPField)bind;
						bindClass = field.getClassOwner();	
					}

					if (bind instanceof ICPPClassType) {
						bindClass = (ICPPClassType)bind;	
					}
					if ((bindClass != null)
						&& (listOfClassReferences.indexOf(bindClass) < 0)
						&& (!bindClass.getName().equalsIgnoreCase(classData.name))){
						listOfClassReferences.add(bindClass);
						listOfCorrespondingFileNames.add(filename);
					}

					
				}
			
			Iterator<ICPPClassType> iter = listOfClassReferences.iterator();
			Iterator<String> iter2 = listOfCorrespondingFileNames.iterator();

			while (iter.hasNext() && iter2.hasNext()) {
				ICPPClassType next = iter.next();
				String file = iter2.next();
				
		// Temporary SOLUTION
		// There is no restriction support
		/*		if (!IsAcceptableFile(file, pathsList)) {
					debug.Debug("R:5");
					continue;
				}
				
		*/
				debug.Debug("R:6" + file);
				boolean isAssociation = false;
				boolean isAggregation = false;
				boolean isComposition = false;
				boolean isDependency  = false;

				// 0 - aggregation
				// 1 - composition
				// -1 - nothing
				int assType = HasAssociationRelation(next, classData.file.project,
						file, classData.name);
				
				if (assType == 1) {
					isComposition = true;
					debug.Debug("Composition");
				} else 
				// Check that 
				if (assType == 0) {
					
					if (isSingletone){
						isDependency = true;
						debug.Debug("Dependency 1");
					} else					
					if (HasAssociationRelation(class1, classData.file.project, 
							classData.file.path, next.getName()) == 0) {
						debug.Debug("Association");
						isAssociation = true;
					} else {
						debug.Debug("Aggregation");
						isAggregation = true;
					}					
				} else {
					debug.Debug("Dependency 2");
					isDependency = true;
				}
				
				debug.Debug("R:10");
				if ((isAggregation && isAggregationSearch)
						|| (isAssociation && isAssociationSearch)
						|| (isComposition && isCompositionSearch)
						|| (isDependency && isDependencySearch)) {
					
					TClassDescriptor res = new TClassDescriptor();
					String file2 = file.substring(file.indexOf(classData.file.project) +  
							classData.file.project.length() + 1, file.length());
					res.file.path = file2;
					res.name = next.getName();
					res.file.project = classData.file.project;
					debug.Debug("R:11");
					result.add(res);
				}
			}
		} catch (CoreException e) {
			debug.Debug("R:13");
		} catch (InterruptedException e) {
			debug.Debug("R:14");
		} catch (DOMException e) {
			debug.Debug("R:15");
		} finally {
			if (index != null)
				index.releaseReadLock();
		}
		debug.Debug("R:16");
		return TU.DynamcCastListToArray(result);
	}

	private IIndexName GetClassFromFile(IIndexFile file, IIndex index) {
		IIndexName ret = null;
		try {
			IIndexName[] names = file.findNames(0, Integer.MAX_VALUE);
			for (int i=0; (names != null) && (i<names.length); ++i) {
				IIndexBinding bind = index.findBinding(names[i]);
				if (bind instanceof ICPPClassType) {
					ret  = names[i];
				}
			}
		} catch (CoreException e) {
			debug.Error("There is no classes in file");
		}
		return ret;
	}

	private int HasAssociationRelation(ICPPClassType next, String projectName, String filename, String className) {
		IField[] fields;
		debug.Error("HasAss:" + className + " in " + next.getName());
		try {
			fields = next.getFields();
			for (int j=0; (fields != null) && (j<fields.length); ++j) {
				if (fields[j].getType() != null) {
					String type = fields[j].getType().toString();
					
					debug.Error("Field: " + type +
							" Name: " + fields[j].getName() +
							" CompType: " + fields[j].getCompositeTypeOwner().toString());
 					if (type.equalsIgnoreCase(className)) {
						return 1; //Composition
					} else if (type.contains(className)) {
						return 0; //Association
					}
				}
			}
		} catch (DOMException e) {
			debug.Error("HasAss: No fields found");
		}
		return TU.HasAssociationRelation(projectName, filename, className, next.getName());
	}

	private void GetClassListFromReference(IIndexName indexName, IIndex index) {
		try {
			debug.Debug("Checking: " + indexName.getFileLocation().getFileName());
			IIndexName[] names = indexName.getFile().findNames(0, Integer.MAX_VALUE);
			for (int i=0; i<names.length;++i) {
				IIndexBinding bind = index.findBinding(names[i]);
				if (bind instanceof ICPPClassType) {
					debug.Note("found class: " + bind.getName());
				}
				
			}
			
		} catch (CoreException e) {
			debug.Error("Sheet happens");
		}
		
	}

	private ICPPClassType GetNestedClassBinding(TClassDescriptor desc){
		// namespace now is a part of TClassDescriptor 
		// and it is clear the right path to class
		// May be not so clear but some thing aout it ... 

		String[] classOwner = desc.name.split("::");
		TClassDescriptor tmpClassData = new TClassDescriptor();
		tmpClassData.file = new TFileDescriptor();
		tmpClassData.file.path = desc.file.path;
		tmpClassData.name = classOwner[0];
		tmpClassData.file.project = desc.file.project;

		debug.Debug("Get Class Binding: " + tmpClassData.name);
		ICPPClassType baseClass = GetClassBinding(tmpClassData);
		
		if (baseClass != null) {
			debug.Debug("Found class " + baseClass.getName());
			return baseClass;
		}
		
		int i =0;
		
		if ((baseClass == null) && (classOwner.length > 1)) {
			ICPPNamespace nspace = this.GetNamespaceBinding(tmpClassData);
			if (nspace != null) {
				try {
					IBinding[] members = nspace.getMemberBindings();
					for (int j = 0; (members != null) && (j< members.length); ++j) {
						if (classOwner[1].equals(members[j].getName()) 
								&& (members[j] instanceof ICPPClassType)) 
						{
							baseClass = (ICPPClassType)members[j];
							i = 1;
							break;
						}
					}
				} catch (DOMException e) {
					debug.Debug("exception namespace get members");
				}
			}
		}
		
		for (; (i<classOwner.length-1) && (baseClass !=null); ++i) {
			ICPPClassType[] nested;
			try {
				nested = baseClass.getNestedClasses();
				baseClass = null;
				for (int j=0; j<nested.length; ++j) {
					if (nested[j].getName().equalsIgnoreCase(classOwner[i+1])) {
						baseClass = nested[j];
					}
				}
			} catch (DOMException e) {
				baseClass = null;
				e.printStackTrace();
			}
		}
		
		
		return baseClass;		
	}

	private ICPPNamespace GetNamespaceBinding(TClassDescriptor data) {
		IIndex index = GetProjectIndex(data);
		ICPPNamespace  cppNamespace = null;

		if (data == null || data.name == null || index == null) {
			debug.Debug("something null");
			return null;
		}


		
		IBinding[] bindings = null;
		try {
			bindings = index.findBindings(data.name.toCharArray(), 
					IndexFilter.ALL_DECLARED_OR_IMPLICIT, null);
		} catch (CoreException e1) {
			debug.Debug("Find namespace binding exception");
		}

		if (bindings != null) {
			for (int  binding = 0;  binding < bindings.length; binding++) {
				if (bindings[binding] instanceof ICPPNamespace) {
					cppNamespace = (ICPPNamespace) 	index.adaptBinding(bindings[binding]);
				}
			}
		}
		return cppNamespace;
	}
	
	private ICPPClassType GetClassBinding(TClassDescriptor data) {
		IIndex index = GetProjectIndex(data);
		ICPPClassType  iClassType = null;

		if (data == null || data.name == null || index == null) {
			debug.Debug("something null");
			return null;
		}
        
		try {			
			index.acquireReadLock();
			IBinding[] bindings = 
				index.findBindings(data.name.toCharArray(), IndexFilter.ALL_DECLARED_OR_IMPLICIT, null);

			if (bindings != null)
			{
				for (int  binding = 0;  binding < bindings.length; binding++)  
				{
					if  (bindings[binding] instanceof ICPPClassType)
					{						
						iClassType = (ICPPClassType)  index.adaptBinding(bindings[binding]);
						return iClassType;						
					}
				}
			} else {
				debug.Debug("binding null");
			}
		} catch (CoreException e) {
			debug.Debug("core exception");
		} catch (InterruptedException e) {
			debug.Debug("interrupted exception");
		} finally {
			if (index != null)
				index.releaseReadLock();
		}

		return null;		
	}

	public String[] findFunctionDeclaration(ICProject project, String name) throws CoreException
	{
		IIndexManager manager = CCorePlugin.getIndexManager();
		IIndex index = manager.getIndex(project);

	    try {
			index.acquireReadLock();
			IBinding[] bindings = index.findBindings(name.toCharArray(), IndexFilter.ALL, null);
	    
			for (int  binding = 0;  binding < bindings.length; binding++)  
			{
				if  (bindings[binding] instanceof IFunction)  
				{
					IFunction  ifunction = (IFunction)  bindings[binding];
					IIndexName[] names = index.findNames(ifunction, IIndex.FIND_DEFINITIONS);
				}
			}
		} catch (InterruptedException e) {
		} finally  {
		    if  (index  !=  null)
		      index.releaseReadLock();
		}
		return null;
	}
	
	public IIndex GetProjectIndex(TClassDescriptor desc)
	{
		ICModel cModel= CoreModel.getDefault().getCModel();
		IIndexManager manager = CCorePlugin.getIndexManager();

		ICProject cProject = null;

		try {
			if (desc.file.project != null) {
				cProject = cModel.getCProject(desc.file.project);
			}
			else {
				cProject = cModel.getCProject();
			}
			
			if (cProject == null) {
				debug.Error("Can not find cModel of project: " + desc.file.project);
			}

			return manager.getIndex(cProject);			
		} catch (Exception e) {
			debug.Error("Exception " + e.getLocalizedMessage());
		}
		return null;
	}
	
	public IASTFileLocation OpenMethodImplementation(TClassDescriptor data,
			String methodName, boolean flag) {
		ICPPClassType found = this.GetNestedClassBinding(data);

		try {
			ICPPMethod[] methods = found.getMethods();
			ICPPMethod foundMethod = null;
			for (int i=0; i < methods.length; ++i) {
				debug.Debug("methname:" + methods[i].getName());
				if ((methods[i].getName() != null) 
					&& (methods[i].getName().equalsIgnoreCase(methodName))) {
					foundMethod = methods[i];
					break;
				}
			}
			if (foundMethod == null) {
				debug.Debug("method not found");
				return null;
			}
			
			IIndex index= GetProjectIndex(data);
			
			IIndexName[] references = index.findDeclarations(foundMethod);
			IIndexName[] decl2 = index.findDeclarations(foundMethod);
			
			
			for (int i=0; i<references.length; ++i) {
				IASTFileLocation floc = references[i].getFileLocation();
				if (floc != null) {
					debug.Debug("Ref: " + floc.getFileName());
				} else {
					debug.Error("RefNull: ");
				}
				
				if (!references[i].isDefinition()) {
					if (flag) {
						IASTFileLocation loc = references[i].getFileLocation();
						int t = loc.getEndingLineNumber();
						t = loc.getStartingLineNumber();
						t = loc.getNodeLength();
						t = loc.getNodeOffset();
						t++;
						FileOpener fopener = new FileOpener();
						fopener.name = references[i].getFileLocation().getFileName();

						PlatformUI.getWorkbench().getDisplay().syncExec(fopener);
						return null;
					} else {
						return references[i].getFileLocation();
					}
				}
			}

		} catch (DOMException e1) {

		} catch (CoreException e) {
		}
		return null;
	}

	public TClassDescriptor[] GetClassDependency(TClassDescriptor data, String[] pathsList)
	{
		boolean isDependencySearch = false;
		
		boolean isSingletone = false; //this.IsSingletoneClass(classData);
		boolean isInterface = this.IsInterface(data);
		
		
		ICPPClassType class1 = this.GetNestedClassBinding(data);
		
		IIndex index = this.GetProjectIndex(data);
		
		if (class1 == null || index == null) {
			debug.Debug("R:2 NULL binding ? ");
			return null;		
		}

		List<ICPPClassType> listOfClassReferences = new ArrayList<ICPPClassType>();
		List<String> listOfCorrespondingFileNames = new ArrayList<String>();
		List<TClassDescriptor> result = new ArrayList<TClassDescriptor>();
		
		try {
			index.acquireReadLock();

			TClassDescriptor[] ret = null;

			IIndexName[] references = index.findNames(class1, IIndex.FIND_ALL_OCCURRENCES);

			if ((references != null) && (references.length > 0))
				for (int i = 0; i< references.length; i++) {

					if (references[i].isBaseSpecifier()) {
						debug.Debug("R:3" + references[i].getFileLocation().getFileName());
						continue;
					}

					IIndexName encnames = references[i].getEnclosingDefinition();

					if (encnames == null) {
						debug.Debug("R:4" + references[i].getFileLocation().getFileName());
						continue;
					}

					debug.Debug("R:5" + references[i].getFileLocation().getFileName());
					
					String filename = encnames.getFileLocation().getFileName();
					
					IIndexBinding bind = index.findBinding(encnames);
					ICPPClassType bindClass = null;
					
					if (bind instanceof ICPPMethod) {
						ICPPMethod methf = (ICPPMethod)bind;

						IParameter[] params = methf.getParameters();
						
						for (int k=0; (params != null) && (k<params.length); ++k) {
						
							if (params[k].getType() != null) {
								String type = params[k].getType().toString();								
								if (type.contains(data.name)) {
									bindClass = methf.getClassOwner();
									break;
								} 
							}
						}
					} else if (bind instanceof ICPPField) {
						
						ICPPField field = (ICPPField)bind;
						
						if ((field.getType() != null) && (isSingletone)) {
							String type = field.getType().toString();
							
							if (type.equalsIgnoreCase(data.name)) {
								// Do nothing it is composition
							} else if (type.contains(data.name)) {
								bindClass = field.getClassOwner();		
							}
						}
						
					} else if (bind instanceof ICPPClassType) {
						bindClass = (ICPPClassType)bind;	
					}
					if ((bindClass != null)
						&& (listOfClassReferences.indexOf(bindClass) < 0)
						&& (!bindClass.getName().equalsIgnoreCase(data.name))){
						listOfClassReferences.add(bindClass);
						listOfCorrespondingFileNames.add(filename);
					}
				}
			
			Iterator<ICPPClassType> iter = listOfClassReferences.iterator();
			Iterator<String> iter2 = listOfCorrespondingFileNames.iterator();

			while (iter.hasNext() && iter2.hasNext()) {
				ICPPClassType next = iter.next();
				String file = iter2.next();
				
				if (!IsAcceptableFile(file, pathsList)) {
					debug.Debug("R:5");
					continue;
				}
				debug.Debug("R:6" + file);
				boolean isAssociation = false;
				boolean isAggregation = false;
				boolean isDependency  = false;
				
				IField[] fields = next.getFields();
				for (int j=0; j<fields.length; ++j) {
					if (fields[j].getType() != null) {
						debug.Debug("R:6.1");
						String type = fields[j].getType().toString();
						debug.Debug("R:6.2");
						if (type.equalsIgnoreCase(data.name)) {
							debug.Debug("R:6.3");
							isAggregation = true;
						} else if (type.contains(data.name)) {
							debug.Debug("R:6.4");
							isAssociation = true;
						}
					}
				}
				debug.Debug("R:7");
				ICPPMethod[] methds = next.getMethods();
				for (int j=0; j<methds.length; ++j) {

					IParameter[] params = methds[j].getParameters();
					
					for (int k=0; k<params.length; ++k) {
					
						if (params[k].getType() != null) {
							String type = params[k].getType().toString();
							
							if (type.contains(data.name)) {
								isDependency = true;
							} 
						}
					}
					
					String ftype = methds[j].getType().toString();
					if (ftype.contains(data.name)) {
						isAssociation = true;
					}
				}
				debug.Debug("R:8");
				if ( !isAssociation && !isDependency && !isAggregation) {
					// if type mentioned this class, but 
					// there is no dependency in fields and methods
					// therefore it is dependency
					debug.Debug("R:9");
					isDependency = true;
				}

				
				debug.Debug("R:10");
				if (isDependency) {
					
					TClassDescriptor res = new TClassDescriptor();
					String file2 = file.substring(file.indexOf(data.file.project) +  
							data.file.project.length(), file.length());
					res.file.path = file2;
					res.name = next.getName();
					res.file.project = data.file.project;
					debug.Debug("R:11");
					result.add(res);
				}
			}
		} catch (CoreException e) {
			debug.Debug("R:13");
		} catch (InterruptedException e) {
			debug.Debug("R:14");
		} catch (DOMException e) {
			debug.Debug("R:15");
		} finally {
			if (index != null)
				index.releaseReadLock();
		}
		debug.Debug("R:16");
		return TU.DynamcCastListToArray(result);
	}

	
}
